//--------------------------------------------
//--------------------------------------------
//--                                        --
//--                                        --
//--    University of Dayton Advanced       --
//--            Rocket Team                 --
//--         Launch Controller              --
//--             09/18/2008                 --
//--                                        --
//--       Written By: Jared Szechy         --
//--                                        --
//--                                        --
//--------------------------------------------
//--------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace UDART
{
    public partial class Form1 : Form
    {
        #region Rocket Commands
        public static string STATUS = "S";
        public static string HELIUM_OPEN = "h";
        public static string HELIUM_CLOSE = "H";
        public static string VENT_OPEN = "v";
        public static string VENT_CLOSE = "V";
        public static string ENGINE_OPEN = "e";
        public static string ENGINE_CLOSE = "E";
        public static string IGNITOR = "I";
        public static string PARACHUTE = "PAR";
        public static string ABORT = "ABORT";
        #endregion

        #region Status Variables
        public enum Valve { Open, Close };
        public enum ValveType { Helium, Fuel, Lox, Engine };
        public int HeliumPressure;
        public int FuelPressure;
        public int LoxPressure;
        public int EnginePressure;
        public int Temperature;
        public Valve HeliumValve;
        public Valve VentValve;
        public Valve EngineValve;
        public Valve Ignitor;
        public bool enableManual = true;
        public bool launchReady = false;
        public bool loxPressure = false;
        public bool fuelPressure = false;
        public bool heliumPressure = false;
        public bool ignTemperature = false;
        public bool launchStarted = false;
        #endregion

        #region Class Variables
        public Configuration _config = new Configuration();
        public Comm _comm = new Comm();
        public Thread tempThread;
        public Thread tempLaunchThread;
        private StreamWriter logStream = null;
        private FileStream logFile;
        public bool updateActive = false;
        public bool comError = false;
        #endregion

        #region Form Initialization
        public Form1()
        {
            InitializeComponent();
            try
            {
                logFile = File.Open("log.txt", FileMode.Append, FileAccess.Write);
                logStream = new StreamWriter(logFile);
                logStream.AutoFlush = true;
            }
            catch (System.IO.IOException)
            {
                MessageBox.Show("Unable to open log file",
                                 "UDART Launch Control",
                                 MessageBoxButtons.OK,
                                 MessageBoxIcon.Error);
            }
        }

        public void Form_Load(object sender, EventArgs e)
        {
            Form1.CheckForIllegalCrossThreadCalls = false;
            DisplaySettings();
            Thread updateThread = new Thread(new ThreadStart(UpdateStatus));
            updateActive = true;
            updateThread.Start();
        }
        #endregion

        #region Update Functions
        public void UpdateStatus()
        {
            string result = "";
            string[] status = new string[10];
            double ratio;
            DateTime start;
            DateTime end;
            tempThread = Thread.CurrentThread;

            while (updateActive)
            {
                result = _comm.SendCommand(STATUS);
                ComLog(STATUS,result);
                if (result == "COMM ERROR" || result == "TIMEOUT")
                {
                    comError = true;
                    result = "0,0,0,0,0,1,0,1,1";
                }
                else
                {
                    comError = false;
                    status = result.Split(',');
                    if (status.Length == 9)
                    {
                        //Helium Pressure
                        HeliumPressure = Int32.Parse(status[0]);
                        ratio = HeliumPressure / 1024.0;
                        HeliumPressure = (int)((5.0 * ratio) * 1258 - 886.2);
                        
                        //Fuel Pressure
                        FuelPressure = Int32.Parse(status[1]);
                        ratio = FuelPressure / 1024.0;
                        FuelPressure = (int)((5.0 * ratio) * 246.82 - 125.74);
                        
                        //LOx Pressure
                        LoxPressure = Int32.Parse(status[2]);
                        ratio = LoxPressure / 1024.0;
                        LoxPressure = (int)((5.0 * ratio) * 246.96 - 132.37);
                        
                        //Engine Pressure
                        EnginePressure = Int32.Parse(status[3]);
                        ratio = EnginePressure / 1024.0;
                        EnginePressure = (int)((5.0 * ratio) * 245.5 - 127.86);
                        
                        //Temperature
                        Temperature = Int32.Parse(status[4]);
                        ratio = Temperature / 1024.0;
                        ratio = (5.0 * ratio);
                        Temperature = (int)KtypeConvert(ratio);

                        HeliumValve = (Valve)Int32.Parse(status[5]);
                        VentValve = (Valve)Int32.Parse(status[6]);
                        EngineValve = (Valve)Int32.Parse(status[7]);
                        Ignitor = (Valve)Int32.Parse(status[8]);
                    }
                    else
                    {
                        comError = true;
                    }
                }
                UpdateDisplay();
                // timer
                start = DateTime.Now;
                end = start.AddMilliseconds(_config.Interval);
                while (DateTime.Now < end)
                {
                    Application.DoEvents();
                }
            }
        }

        public double KtypeConvert(double voltage)
        {
            double[] an = {0.226584602, 24152.10900, 67233.4248, 2210340.682, -860963914.9, 4.83506e10, -1.18452e12,
                           1.38690e13, -6.33708e13};
            double sum = 0;
            for (int i = 0; i < 9; i++)
            {
                sum = sum + an[i] * Math.Pow(voltage,i);
            }
            return sum;
        }

        public void UpdateDisplay()
        {
            lblCommError.Visible = comError;
            UpdatePressures();
            UpdateValves();
            UpdateColors();
            UpdateLaunchReady();
        }

        public void UpdatePressures()
        {
            lblHelium.Text = HeliumPressure.ToString();
            lblFuel.Text = FuelPressure.ToString();
            lblLox.Text = LoxPressure.ToString();
            lblEngine.Text = EnginePressure.ToString();
            lblTemperature.Text = Temperature.ToString();
        }

        public void UpdateValves()
        {
            if (HeliumValve == Valve.Close)
                lblHeliumValve.Text = "C";
            else if (HeliumValve == Valve.Open)
                lblHeliumValve.Text = "O";

            if (VentValve == Valve.Close)
                lblFuelValve.Text = "C";
            else if (VentValve == Valve.Open)
                lblFuelValve.Text = "O";

            if (VentValve == Valve.Close)
                lblLoxValve.Text = "C";
            else if (VentValve == Valve.Open)
                lblLoxValve.Text = "O";

            if (EngineValve == Valve.Close)
                lblEngineValve.Text = "C";
            else if (EngineValve == Valve.Open)
                lblEngineValve.Text = "O";

            if (Ignitor == Valve.Close)
                lblIgnitor.Text = "C";
            else if (Ignitor == Valve.Open)
                lblIgnitor.Text = "O";
        }

        public void UpdateColors()
        {
            // Helium
            if (HeliumPressure > _config.Helium_Max || HeliumPressure < _config.Helium_Min)
            {
                lblHelium.ForeColor = Color.Red;
                heliumPressure = false;
            }
            else
            {
                lblHelium.ForeColor = Color.Green;
                heliumPressure = true;
            }

            if (HeliumValve == Valve.Close)
                lblHeliumValve.ForeColor = Color.Green;
            else
                lblHeliumValve.ForeColor = Color.Red;

            // Fuel
            if (FuelPressure > _config.Fuel_Max || FuelPressure < _config.Fuel_Min)
            {
                lblFuel.ForeColor = Color.Red;
                fuelPressure = false;
            }
            else
            {
                lblFuel.ForeColor = Color.Green;
                fuelPressure = true;
            }

            if (VentValve == Valve.Open)
                lblFuelValve.ForeColor = Color.Green;
            else
                lblFuelValve.ForeColor = Color.Red;

            // Lox
            if (LoxPressure > _config.Lox_Max || LoxPressure < _config.Lox_Min)
            {
                lblLox.ForeColor = Color.Red;
                loxPressure = false;
            }
            else
            {
                lblLox.ForeColor = Color.Green;
                loxPressure = true;
            }

            if (VentValve == Valve.Open)
                lblLoxValve.ForeColor = Color.Green;
            else
                lblLoxValve.ForeColor = Color.Red;

            // Engine
            if (EnginePressure > _config.Engine_Max || EnginePressure < _config.Engine_Min)
                lblEngine.ForeColor = Color.Red;
            else
                lblEngine.ForeColor = Color.Black;

            if (EngineValve == Valve.Close)
                lblEngineValve.ForeColor = Color.Green;
            else
                lblEngineValve.ForeColor = Color.Red;

            // Ignitor
            if (Ignitor == Valve.Close)
                lblIgnitor.ForeColor = Color.Green;
            else
                lblIgnitor.ForeColor = Color.Red;

            // Ignitor Temperature
            if (Temperature > _config.Temp_Min)
            {
                lblTemperature.ForeColor = Color.Green;
                ignTemperature = true;
            }
            else
            {
                lblTemperature.ForeColor = Color.Red;
                ignTemperature = false;
            }
        }

        private void UpdateLaunchReady()
        {
            if (Ignitor == Valve.Close)
                if (EngineValve == Valve.Close)
                    if (VentValve == Valve.Open)
                        if (HeliumValve == Valve.Close)
                            if(!launchStarted)
                            {
                                launchReady = true;
                                btnLaunch.Enabled = true;
                                btnLaunch.BackColor = Color.Green;
                                return;
                            }
            launchReady = false;
            btnLaunch.BackColor = System.Drawing.SystemColors.Control;
            btnLaunch.Enabled = false;
        }
        #endregion

        #region Rocket Actions
        // Sends valve commands
        private bool OperateValve(string command)
        {
            tempThread.Suspend();
            string response = "";
            response = _comm.SendCommand(command);
            LogMessage(command, response);
            tempThread.Resume();
            if (response == "OK")
                return true;
            else
                return false;
        }

        // Helium Valve
        private void lblHeliumValve_Click(object sender, EventArgs e)
        {
            if (enableManual)
            {
                if (HeliumValve == Valve.Close)
                {
                    if (MessageBox.Show("Do you want to open the helium valve?",
                                        "Open Helium Valve",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Opening Helium Valve");
                        if (OperateValve(HELIUM_OPEN))
                            HeliumValve = Valve.Open;
                    }
                }
                else if (HeliumValve == Valve.Open)
                {
                    if (MessageBox.Show("Do you want to close the helium valve?",
                                        "Close Helium Valve",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Closing Helium Valve");
                        if (OperateValve(HELIUM_CLOSE))
                            HeliumValve = Valve.Close;
                    }
                }
            }
        }

        // Fuel Vent Valve
        private void lblFuelValve_Click(object sender, EventArgs e)
        {
            if (enableManual)
            {
                if (VentValve == Valve.Close)
                {
                    if (MessageBox.Show("Do you want to open the vent valves?",
                                        "Open Vent Valves",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Opening Vents");
                        if (OperateValve(VENT_OPEN))
                            VentValve = Valve.Open;
                    }
                }
                else if (VentValve == Valve.Open)
                {
                    if (MessageBox.Show("Do you want to close the vent valves?",
                                        "Close Vent Valves",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Closing Vents");
                        if (OperateValve(VENT_CLOSE))
                            VentValve = Valve.Close;
                    }
                }
            }
        }

        // Lox Vent Valve
        private void lblLoxValve_Click(object sender, EventArgs e)
        {
            if (enableManual)
            {
                if (VentValve == Valve.Close)
                {
                    if (MessageBox.Show("Do you want to open the vent valves?",
                                        "Open Vent Valves",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Opening Vents");
                        if (OperateValve(VENT_OPEN))
                            VentValve = Valve.Open;
                    }
                }
                else if (VentValve == Valve.Open)
                {
                    if (MessageBox.Show("Do you want to close the vent valves?",
                                        "Close Vent Valves",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Closing Vents");
                        if (OperateValve(VENT_CLOSE))
                            VentValve = Valve.Close;
                    }
                }
            }
        }

        // Engine Valve
        private void lblEngineValve_Click(object sender, EventArgs e)
        {
            if (enableManual)
            {
                if (EngineValve == Valve.Close)
                {
                    if (MessageBox.Show("Do you want to open the engine valve?",
                                        "Open Engine Valve",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Opening Engine Valve");
                        if (OperateValve(ENGINE_OPEN))
                            EngineValve = Valve.Open;
                    }
                }
                else if (EngineValve == Valve.Open)
                {
                    if (MessageBox.Show("Do you want to close the engine valve?",
                                        "Close Engine Valve",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Closing Engine Valve");
                        if (OperateValve(ENGINE_CLOSE))
                            EngineValve = Valve.Close;
                    }
                }
            }
        }

        // Ignitor Fire
        private void lblIgnitor_Click(object sender, EventArgs e)
        {
            if (enableManual)
            {
                if (Ignitor == Valve.Close)
                {
                    if (MessageBox.Show("Do you want to fire the ignitor?",
                                        "Fire Ignitor",
                                        MessageBoxButtons.YesNo,
                                        MessageBoxIcon.Question,
                                        MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                    {
                        LogMessage("Firing ignitor");
                        OperateValve(IGNITOR);
                    }
                }
            }
        }
        #endregion

        #region Launch Functions
        // Launch Procedure
        private void LaunchProcedure()
        {
            enableManual = false;
            launchStarted = true;
            LogMessage("Launch Sequence Started");
            tempLaunchThread = Thread.CurrentThread;
            LogMessage("Close vents");
            OperateValve(VENT_CLOSE);
            LogMessage("Open helium");
            OperateValve(HELIUM_OPEN);
            waitForPressure();
            LogMessage("Fire ignitor");
            OperateValve(IGNITOR);
            waitForTemperature();
            LogMessage("Open engine valve");
            OperateValve(ENGINE_OPEN);
            enableManual = true;
            launchStarted = false;
            LogMessage("Launch Sequence Finished");
        }

        // Wait for pressure
        private void waitForPressure()
        {
            LogMessage("Waiting for required pressures");
            while (!loxPressure || !fuelPressure || !heliumPressure)
                Application.DoEvents();
            LogMessage("Required pressures have been met");
        }

        // Wait for ignitor temperature
        private void waitForTemperature()
        {
            LogMessage("Waiting for required ignitor temperature");
            while (!ignTemperature)
                Application.DoEvents();
            LogMessage("Required temperature has been met");
        }
        #endregion

        #region Form Functions
        // Display Config File Settings 
        private void DisplaySettings()
        {
            StringBuilder message = new StringBuilder();
            message.Append("COM: " + _config.Com_Port + Environment.NewLine);
            message.Append("Baud Rate: " + _config.Baud_Rate + Environment.NewLine);
            message.Append("Timeout: " + _config.Timeout + " ms" + Environment.NewLine);
            message.Append("Interval: " + _config.Interval + " ms" + Environment.NewLine);
            message.Append("Helium Min: " + _config.Helium_Min + " psi" + Environment.NewLine);
            message.Append("Helium Max: " + _config.Helium_Max + " psi" + Environment.NewLine);
            message.Append("Fuel Min: " + _config.Fuel_Min + " psi" + Environment.NewLine);
            message.Append("Fuel Max: " + _config.Fuel_Max + " psi" + Environment.NewLine);
            message.Append("Lox Min: " + _config.Lox_Min + " psi" + Environment.NewLine);
            message.Append("Lox Max: " + _config.Lox_Max + " psi" + Environment.NewLine);
            message.Append("Engine Min: " + _config.Engine_Min + " psi" + Environment.NewLine);
            message.Append("Engine Max: " + _config.Engine_Max + " psi" + Environment.NewLine);
            message.Append("Min Ign Temp: " + _config.Temp_Min + " F" + Environment.NewLine);
            lblInfo.Text = message.ToString();
        }

        // Initiate Abort Procedure
        private void btnAbort_Click(object sender, EventArgs e)
        {
            LogMessage("Abort Sequence Started");
            enableManual = true;
            if(tempLaunchThread != null)
                if (tempLaunchThread.IsAlive)
                    tempLaunchThread.Abort();
            LogMessage("Close engine valve");
            OperateValve(ENGINE_CLOSE);
            LogMessage("Close helium");
            OperateValve(HELIUM_CLOSE);
            LogMessage("Open vents");
            OperateValve(VENT_OPEN);
            launchStarted = false;
            LogMessage("Abort Sequence Finished");
        }

        // Initiate Launch Sequence
        private void btnLaunch_Click(object sender, EventArgs e)
        {
            Thread launchThread = new Thread(new ThreadStart(LaunchProcedure));
            launchThread.Start();
        }

        // Close Program
        private void btnExit_Click(object sender, EventArgs e)
        {
            updateActive = false;
            tempThread.Join();
            LogMessage("Goodbye!");
            Form1.ActiveForm.Close();
        }

        // About Box
        private void btnAbout_Click(object sender, EventArgs e)
        {
            AboutBox about = new AboutBox();
            about.Show();
        }
        #endregion

        #region Logging Functions
        public TextBox MessageLog
        {
            get { return txtMessages; }
        }

        public void LogMessage(string command, string response)
        {
            MessageLog.AppendText(command + " >> " + response + Environment.NewLine);
            MessageLog.ScrollToCaret();
            logStream.WriteLine("[" + System.DateTime.Now + "] " + command + " >> " + response);
        }

        public void LogMessage(string message)
        {
            MessageLog.AppendText(message + Environment.NewLine);
            MessageLog.ScrollToCaret();
            logStream.WriteLine("[" + System.DateTime.Now + "] M >> " + message);
        }

        public void ComLog(string command, string response)
        {
            logStream.WriteLine("[" + System.DateTime.Now + "] " + command + " >> " + response);
        }
        #endregion
    }
}